function videoFromRecorder (videoUri, title, url_thumbnail) {
	var seesMicUrlNode = document.getElementById('seesmic_url');
	seesMicUrlNode.value = videoUri;

	var divs = seesMicUrlNode.parentNode.getElementsByTagName('div');
	var recorderDiv;

	for (var i=0; i<divs.length; i++) {
		if (lypo.hasClass(divs[i], 'recorder')) {
			recorderDiv = divs[i];
			break;
		}
	}

	recorderDiv.innerHTML = '<img src="' + url_thumbnail + '" />';
	recorderDiv.innerHTML += '<p>Your video has been saved. You can type an additional mesages in the comment field and hit Send</p>';
	
	var spans = document.getElementById('compose-reaction').getElementsByTagName('span');
	for (var i=0; i<spans.length; i++) {
		if (lypo.hasClass(spans[i] ,'disabled')) {
			lypo.removeClass(spans[i], 'disabled');
			break;
		}
	}
}

var lypo = {}

lypo.baseUrl = function () {
	return 'http://<?php echo $basehost ?>';
}


/**
 * Function to determine the full path of a request 
 * @param {Object} path
 */
lypo.url = function (application, path) {
	return lypo.baseUrl() + '/' + application + '.php/' + path;
}


lypo.parseUrl = function (url) {
	url = url.replace(/^http:\/\/[^\/]+/, '');
	return lypo.baseUrl() + url;
}


/**
 * helper function for managing element classnames
 * @param {Object} element
 * @param {String} className
 */
lypo.addClass = function (element, className) {
	var classes = element.className.split(' ');

	for (var i=0; i<classes.length; i++) {
		if (classes[i] == className) return
	}

	classes.push(className);
	element.className = classes.join(' ').replace(/\s+/, ' ');
}


/**
 * helper function for managing element classnames
 * @param {Object} element
 * @param {String} className
 */
lypo.removeClass = function (element, className) {
	var classes = element.className.split(' ');

	for (var i=0; i<classes.length; i++) {
		if (classes[i] == className) delete classes[i];
	}

	element.className = classes.join(' ').replace(/\s+/, ' ');	
}


/**
 * helper function for managing element classnames
 * @param {Object} element
 * @param {String} className
 */
lypo.hasClass = function (element, className) {
	var classes = element.className.split(' ');

	for (var i=0; i<classes.length; i++) {
		if (classes[i] == className) return true;
	}

	return false;
}

lypo.keywords = {
	stringify: function (keywords) {
		var keywordStrings = new Array();

		for (var category in keywords)
			keywordStrings.push(category + '||' + keywords[category].join('|'));

		return keywordStrings.join('#');
	},

	objectify: function (keywords) {
		var keywordObject = {}
		var parts;

		if (keywords == '') return {};

		keywordStrings = keywords.split('#');

		for (var i=0; i<keywordStrings.length; i++) {
			parts = keywordStrings[i].split('||');
			keywordObject[parts[0]] = parts[1].split('|');
		}

		return keywordObject;
	}
}


/**
 * Fixes messed up src attribute in <embed> and <img> tags
 * @param {Object} html
 */
lypo.fixProxyURLs = function (html) {
	var urls, bareUrl;
	var matches = html.match(/\/gadgets\/proxy\?url=([^&]+)/gmi);

	if (!matches || !matches.length) return html;

	for (var i=0; i<matches.length; i++) {
		bareUrl  = matches[i].substring(19);
		cleanUrl = decodeURIComponent(bareUrl);

		html = html.replace(new RegExp('\/gadgets\/proxy\\\?url=' + bareUrl + '[^"]*', 'gmi'), cleanUrl);
	}

	return html;
}


/**
 *  LYPO page object
 * @param {String} pageId
 */
lypo.page = function (pageId) {
	//private variables
	var _domNode;
	var _showCallbacks = new Array();
	var _data = {};

	//if there is no element with id pageId return false
	if ((_domNode = document.getElementById(pageId)) == null) {
		if (console)
			console.error('lypo.page(): No element with id "' + pageId + '"');
		return;
	}

	this.addShowCallback = function (callback) {
		_showCallbacks.push(callback)
	}

	//shows the page
	this.show = function () {
		for (var i=0; i<_showCallbacks.length; i++) {
			_showCallbacks[i].call(this);
		}

		lypo.removeClass(_domNode, 'hide');
	}

	//hides the page
	this.hide = function () {
		lypo.addClass(_domNode, 'hide');
	}

	//stores some data for the page
	this.store = function(key, data){
		_data[key] = data;
	}

	//retrieves data for the page	
	this.retrieve = function (key) {
		return _data[key] ? _data[key] : false;
	}
}



/**
 * LYPO section object
 * @param {String} sectionId
 */
lypo.section = function (sectionId) {
	//private variables
	var _domNode;
	var _panelEvents = {};
	var _data = {};

	//if there is no element with id pageId return false
	if ((_domNode = document.getElementById(sectionId)) == null) {
		if (console)
			console.error('lypo.section(): No element with id "' + sectionId + '"');
		return;
	}

	//captures a click on the section and calls the callback functions associated with the element
	function _dispatchClick (e) {
		var amountCallbacks;
		var evt = e || window.event;
		var elm = evt.target || evt.srcElement;
		var selectors = elm.className.split(' ');

		for (var i=0; i<selectors.length; i++)
			selectors[i] = '.' + selectors[i];

		if (elm.id != '')
			selectors.push('#' + elm.id);

		for (var i=0; i<selectors.length; i++) {
			if (_panelEvents[selectors[i]]) {
				amountCallbacks = _panelEvents[selectors[i]].length;

				for (var j=0; j<amountCallbacks; j++) {
					_panelEvents[selectors[i]][j].call(elm, evt);
				}
			}
		}
	}

	//register click event
	_domNode.onclick = _dispatchClick;

	//registers the callback functions for clicks on elements in the section
	this.addClickCallback = function (selector, callback) {
		if (!_panelEvents[selector])
			_panelEvents[selector] = new Array();

		_panelEvents[selector].push(callback);
	}

	//gets the content for this panel from the LYPO server
	this.update = function(contentPath, callback){
		gadgets.io.makeRequest(contentPath, function (response) {
			_domNode.innerHTML = lypo.fixProxyURLs(response.text);
			_data = response.data;

			if (callback) callback();
		});
	}

	//stores some data for the page
	this.store = function(key, data){
		_data[key] = data;
	}
	
	this.retrieve = function (key) {
		return _data[key] ? _data[key] : false;
	}
}



/**
 * THE GADGET OBJECT
 */
lypo.gadget = (function () {
	//private variables
	var _loading = false;
	var _pages = {};
	var _loadingTimeout;
	var pageTracker;
	var _profileData = {
		lypo_signature: ''
	};



	/**
	 * ANONYMOUS FUNCTION TO GENERATE A FUNCTION THAT RETRIEVES USER INFO FROM SOCIAL NETWORK
	 */
	var _getSocialNetworkData = (function () {
		if (opensocial) {
			return function (callback) {
				var os = opensocial;
				var params = {}

				//limit the fields to be fetched. Saves on bandwidth in the response
				params[os.DataRequest.PeopleRequestFields.PROFILE_DETAILS] = [
					os.Person.Field.ID,
					os.Person.Field.NAME,
					os.Person.Field.GENDER,
					os.Person.Field.AGE,
					os.Person.Field.DATE_OF_BIRTH,
					os.Person.Field.JOBS,
					os.Person.Field.THUMBNAIL_URL];

				var req = os.newDataRequest();
				req.add(req.newFetchPersonRequest('VIEWER', params), 'viewer');
				req.send(function (response) {
					var viewer = response.get('viewer').getData();

					if (viewer) {
						_profileData.userid = viewer.getId() + '@' + os.getEnvironment().getDomain();
						_profileData.name = '';
						_profileData.gender = '';
						_profileData.origin = '';
						_profileData.country = '';

						if (typeof viewer.getField(os.Person.Field.NAME) == 'string') {
							_profileData.name = viewer.getField(os.Person.Field.NAME)
						} else if (viewer.getField(os.Person.Field.NAME).getField(os.Name.Field.GIVEN_NAME)) {
							_profileData.name = viewer.getField(os.Person.Field.NAME).getField(os.Name.Field.GIVEN_NAME);
						} else {
							_profileData.name = 'Anonymous';
						}

						if (viewer.getField(os.Person.Field.GENDER)) {
							if (viewer.getField(os.Person.Field.GENDER)[0] == 'M' || viewer.getField(os.Person.Field.GENDER)[0] == 'F') {
								_profileData.gender = viewer.getField(os.Person.Field.GENDER)[0].toLowerCase();
							} else if (viewer.getField(os.Person.Field.GENDER).getDisplayValue()[0]) {
								_profileData.gender = viewer.getField(os.Person.Field.GENDER).getDisplayValue()[0];
							}
						}

						if (viewer.getField(os.Person.Field.ADDRESSES) && viewer.getField(os.Person.Field.ADDRESSES)[0].getField(os.Address.Field.COUNTRY))
							_profileData.country = viewer.getField(os.Person.Field.ADDRESSES)[0].getField(os.Address.Field.COUNTRY);

						_profileData.thumbnail_url = viewer.getField(os.Person.Field.THUMBNAIL_URL);
						_profileData.enemy = '';
						
						var occupations = new Array();
						var schools = viewer.getField(os.Person.Field.SCHOOLS);
						var jobs = viewer.getField(os.Person.Field.JOBS);
						var endDate = '';
						var dateObj = new Date();
						var today = '';
						today += dateObj.getFullYear();
						today += dateObj.getMonth() + 1 < 10 ? '0' + (dateObj.getMonth() + 1).toString() : (dateObj.getMonth() + 1).toString();
						today += dateObj.getDate() < 10 ? '0' + dateObj.getDate() : dateObj.getDate();

						for (var i in schools) {
							endDate = schools[i].getField(os.Organization.Field.END_DATE).replace(/-/g, '');
							
							if (endDate == null || endDate > today) occupations.push(schools[i].getField(os.Organization.Field.TITLE));
						}
						
						for (var i in jobs) {
							endDate = jobs[i].getField(os.Organization.Field.END_DATE).replace(/-/g, '');
							
							if (endDate == null || endDate > today) occupations.push(jobs[i].getField(os.Organization.Field.TITLE));
						}

						//if age was not set by the container determine it from the DoB
						_profileData.age = viewer.getField(os.Person.Field.AGE);
						var dateOfBirth = viewer.getField(os.Person.Field.DATE_OF_BIRTH);

						if (_profileData.age == undefined) {
							if (dateOfBirth && dateOfBirth != null) {
								var birthDay = '';
								birthDay += dateOfBirth.getFullYear();

								if (dateOfBirth.getMonth() + 1 < 10)
									birthDay += '0' + (dateOfBirth.getMonth() + 1).toString();
								else
									birthDay += dateOfBirth.getMonth().toString();

								birthDay += dateOfBirth.getDate() < 10 ? '0' + dateOfBirth.getDate() : dateOfBirth.getDate();

								if (birthDay != today && birthDay.length == 8)
									_profileData.age = Math.floor((today - birthDay) / 10000);
							} else {
								_profileData.age = '';
							}
						}

						_profileData.occupation = occupations.join(', ');
					}

					if (callback) callback();
				});
			}
		} else {
			return function () {
				if (console)
					console.error('No profile library found');
			}
		}
	})()


	/**
	 * Gets the userdata from the LYPO server
	 * @param {Object} callback Callback function to call when done
	 */
	var _getLypoData = function (callback) {
		gadgets.io.makeRequest(lypo.url('api', 'user/get?userid=' + _profileData.userid), callback);
	}


	/**
	 * Sends the profile data to the LYPO server
	 * @param {Object} callback The function to call when done
	 */
	var _storeLypoData = function (type, callback) {
		var url;
		if (type == 'update') {
			url = lypo.url('api', 'user/update');
		} else if (type == 'create') {
			url = lypo.url('api', 'user/create');
		} else {
			throw new Error('Incorrect storage type');
		}

		var values = [];
		var keyValue = {};

		_profileData.keywords = lypo.keywords.stringify(_profileData.keywords);

		for (var i in _profileData) {
			keyValue = {};
			keyValue[i] = _profileData[i];

			if (type == 'update' && i == 'lypo_signature')
				continue;

			values.push(gadgets.io.encodeValues(keyValue));
		}

		document.getElementById('nametag').getElementsByTagName('img')[0].src = _profileData.thumbnail_url;
		document.getElementById('nametag').getElementsByTagName('span')[0].innerHTML = _profileData.name;

		var params = {}
		params[gadgets.io.RequestParameters.POST_DATA] = values.join('&');
		params[gadgets.io.RequestParameters.METHOD]    = gadgets.io.MethodType.POST;

		gadgets.io.makeRequest(url, function () {
			if (type == 'create')
				_track('Registration', 'complete');

			if (callback) callback();
		}, params);
	}


	/**
	 * SETS BEHAVIOURS ON THE YES/NO BUTTONS IN DEBATES
	 * @param {String} parentNodeId
	 */
	var _setDebateOptionsBehaviours = function (parentNodeId) {
		var debateParent = document.getElementById(parentNodeId);
		var pNodes = debateParent.getElementsByTagName('p');
		var opinionOptions;

		for (var i=0; i<pNodes.length; i++) {
			if (lypo.hasClass(pNodes[i], 'opinion-options')) {
				opinionOptions = pNodes[i];
				break;
			}
		}

		for (var span = opinionOptions.firstChild; span!=null; span=span.nextSibling) {
			if (span.nodeName == '#text') continue;

			if (lypo.hasClass(span, 'vote-yes')) {
				span.onmouseover = function () {
					lypo.addClass(this, 'vote-yes-mouseover');
				}

				span.onmouseout = function () {
					lypo.removeClass(this, 'vote-yes-mouseover');
				}
			} else if (lypo.hasClass(span, 'vote-no')) {
				span.onmouseover = function () {
					lypo.addClass(this, 'vote-no-mouseover');
				}

				span.onmouseout = function () {
					lypo.removeClass(this, 'vote-no-mouseover');
				}
			}
		}
	}


	/**
	 * Sets the active menu item
	 */
	var _setActiveMenuItem = function (menuItem) {
		var classNames = {
			'home': 'to-home',
			'debates': 'to-debates',
			'my-profile': 'to-profile',
			'my-opposites': 'to-opposites',
			'about-lypo': 'to-about'}

		var nav = document.getElementById('navigation');

		for (var li=nav.firstChild; li!=null; li=li.nextSibling) {
			if (li.nodeName != '#text') {
				if (lypo.hasClass(li, classNames[menuItem])) {
					lypo.addClass(li, 'active');
				} else {
					lypo.removeClass(li, 'active');
				}
			}
		}
	}


	/**
	 * wrapper function to track usage
	 */
	var _track = function () {
		pageTracker._trackEvent.apply(this,arguments)
	}


	/**
	 * BUILDS THE PAGE WHERE THE USER CHOSES HOW TO REGISTER
	 */
	var _buildPreRegChoice = function () {
		_pages['preregister-choice'] = new lypo.page('preregister-choice');
		var section = new lypo.section('preregister-choice');

		section.addClickCallback('.new-user', function () {
			lypo.gadget.showLoading();

			_buildStatementsPage();
			_buildPersonalInfoPage();

			lypo.gadget.goToPage('register-statements');
		});

		section.addClickCallback('.existing-user', function () {
			lypo.gadget.showLoading();

			_buildPreRegConnect();

			lypo.gadget.goToPage('preregister-connect');
		});
	}


	var _buildPreRegConnect = function () {
		_pages['preregister-connect'] = new lypo.page('preregister-connect');
		_pages['preregister-connect'].addShowCallback(function () {
			lypo.gadget.hideLoading();
		});

		var section = new lypo.section('preregister-connect');

		section.addClickCallback('.submit-code', function () {
			var submitBtn   = this;
			var inputs      = document.getElementById('preregister-connect').getElementsByTagName('input');
			var connectCode = '';
			var errorSpan   = submitBtn.nextSibling;

			for (var i=0; i<inputs.length; i++) {
				if (lypo.hasClass(inputs[i], 'connect-code')) {
					connectCode = inputs[i].value;
					break;
				}
			}

			if (connectCode != '') {
				gadgets.io.makeRequest(lypo.url('api', 'user/networkmerge?code=' + connectCode + '&userid=' + _profileData.userid), function (response) {
					eval('var data = ' + response.data);

					if (data.message != '') {
						errorSpan.innerHTML = data.message;
					} else {
						lypo.gadget.showLoading();
						_getLypoData(function (response) {
							eval('var lypoData = ' + response.data);

							_profileData.name       = lypoData.data.user.name;
							_profileData.age        = lypoData.data.user.age;
							_profileData.gender     = lypoData.data.user.gender;
							_profileData.origin     = lypoData.data.user.origin;
							_profileData.occupation = lypoData.data.user.occupation;
							_profileData.enemy      = lypoData.data.user.enemy;
							_profileData.keywords   = lypo.keywords.objectify(lypoData.data.user.keywords);
							_profileData.thumbnail_url = lypoData.data.user.thumbnail_url;

							document.getElementById('nametag').getElementsByTagName('span')[0].innerHTML = _profileData.name;
							document.getElementById('nametag').getElementsByTagName('img')[0].src = _profileData.thumbnail_url;

							lypo.removeClass(document.getElementById('navigation'), 'hide');

							document.getElementById('register-statements').parentNode.removeChild(document.getElementById('register-statements'));
							document.getElementById('register-info').parentNode.removeChild(document.getElementById('register-info'));

							lypo.gadget.goToPage('home');
						});
					}
				});
			} else {
				errorSpan.innerHTML = 'You haven\'t entered a code';
			}
		});

		section.addClickCallback('.go-to-network', function () {
			var selectElements = document.getElementById('preregister-connect').getElementsByTagName('select');
			var networkUrl = selectElements[0].options[selectElements[0].selectedIndex].value;

			window.open(networkUrl);
		});

		section.addClickCallback('.regular-registration', function () {
			lypo.gadget.showLoading();

			_buildStatementsPage();
			_buildPersonalInfoPage();

			lypo.gadget.goToPage('register-statements');
		});
	}


	/**
	 * BUILDS THE REGISTER PAGE
	 */
	var _buildStatementsPage = function () {
		var statements, statement, position, currentStatement;
		var numStatements = 0;
		var positions = {};
		var agreeBtn, disagreeBtn, nextBtn, prevBtn;

		//create the page and section objects
		_pages['register-statements'] = new lypo.page('register-statements');
		var section = new lypo.section('register-statements');

		_pages['register-statements'].addShowCallback(function () {
			_track('Registration', 'start');
			lypo.gadget.hideLoading();
		});

		//chop up the string with statements and positions into a key/value object
		var signaturePairs = _profileData.lypo_signature.split(' ');

		if (signaturePairs) {
			for (var i=0; i<signaturePairs.length; i++) {
				signaturePairs[i] = signaturePairs[i].replace(/^0+/g, '');

				statement = signaturePairs[i].substring(0, signaturePairs[i].length - 1);
				position  = signaturePairs[i][signaturePairs[i].length - 1];

				positions[statement] = position;
			}
		}

		//Create references to all the buttons will come in handy later on
		var buttons = document.getElementById('statement-options').getElementsByTagName('span');

		for (var i=0; i<buttons.length; i++) {
			buttons[i].onmouseover = buttonHover;
			buttons[i].onmouseout  = buttonHover;

			if (lypo.hasClass(buttons[i], 'agree')) {
				agreeBtn = buttons[i];
			} else if (lypo.hasClass(buttons[i], 'disagree')) {
				disagreeBtn = buttons[i];
			} else if (lypo.hasClass(buttons[i], 'prev-step')) {
				prevBtn = buttons[i];
			} else if (lypo.hasClass(buttons[i], 'next-step')) {
				nextBtn = buttons[i];
			}
		}

		//callback function to handle the setting and removing of classnames on mouse(over|out)
		function buttonHover (e) {
			e = e || window.event;

			var buttonClass;

			if (lypo.hasClass(this, 'agree')) {
				buttonClass = 'agree';
			} else if (lypo.hasClass(this, 'disagree')) {
				buttonClass = 'disagree';
			} else if (lypo.hasClass(this, 'prev-step')) {
				buttonClass = 'prev-step';
			} else if (lypo.hasClass(this, 'next-step')) {
				buttonClass = 'next-step';
			}

			if (e.type == 'mouseover' && !lypo.hasClass(this, buttonClass + '-active')) {
				lypo.addClass(this, buttonClass + '-rollover');
			} else if (e.type == 'mouseout') {
				lypo.removeClass(this, buttonClass + '-rollover');
			}
		}

		//callback handler for click on the agree/disagree buttons
		function positionOnStatement () {
			if (lypo.hasClass(this, 'agree')) {
				positions[statements[currentStatement].id] = 'a';

			} else if (lypo.hasClass(this, 'disagree')) {
				positions[statements[currentStatement].id] = 'c';
			}

			prevBtn.style.display = 'block';

			if (currentStatement == statements.length-1) {
				var lypoSignature = '';
				for (var i in positions) {
					lypoSignature += i < 100 ? '0' : '';
					lypoSignature += i < 10 ? '0' : '';
					lypoSignature += i + positions[i] + ' ';
				}

				_profileData.lypo_signature = lypoSignature.replace(/\s+$/, ''); //strip whitespace at the end

				lypo.gadget.goToPage('register-info');
			} else {
				currentStatement++;
				var statementString = '"' + statements[currentStatement].text + '" (' + (currentStatement+1).toString()+ '/' + statements.length + ')';
				document.getElementById('currentstatement').innerHTML = statementString;

				lypo.removeClass(disagreeBtn, 'disagree-active');
				lypo.removeClass(agreeBtn, 'agree-active');

				if (positions[statements[currentStatement].id] == 'a') {
					lypo.addClass(agreeBtn, 'agree-active');
				} else if (positions[statements[currentStatement].id] == 'c') {
					lypo.addClass(disagreeBtn, 'disagree-active');
				}
			}
		}

		//add the callbacks for the buttons
		section.addClickCallback('.agree', positionOnStatement);
		section.addClickCallback('.disagree', positionOnStatement);

		//if there is no previous answer set 'i don't know' answer
		section.addClickCallback('.next-step', function () {
			if (!positions[statements[currentStatement].id] || positions[statements[currentStatement].id] == '')
				positions[statements[currentStatement].id] = 'b';

			prevBtn.style.display = 'block';

			if (currentStatement == statements.length-1) {
				var lypoSignature = '';
				for (var i in positions) {
					lypoSignature += i < 100 ? '0' : '';
					lypoSignature += i < 10 ? '0' : '';
					lypoSignature += i + positions[i] + ' ';
				}

				_profileData.lypo_signature = lypoSignature.replace(/\s+$/, ''); //strip whitespace at the end

				lypo.gadget.goToPage('register-info');
			} else {
				currentStatement++;
				var statementString = '"' + statements[currentStatement].text + '" (' + (currentStatement+1).toString()+ '/' + statements.length + ')';
				document.getElementById('currentstatement').innerHTML = statementString;

				lypo.removeClass(disagreeBtn, 'disagree-active');
				lypo.removeClass(agreeBtn, 'agree-active');

				if (positions[statements[currentStatement].id] == 'a') {
					lypo.addClass(agreeBtn, 'agree-active');
				} else if (positions[statements[currentStatement].id] == 'c') {
					lypo.addClass(disagreeBtn, 'disagree-active');
				}
			}
		});

		// go to the previous question
		section.addClickCallback('.prev-step', function () {
			currentStatement--;

			if (currentStatement == 0)
				prevBtn.style.display = 'none';

			nextBtn.style.display = 'block';

			var statementString = '"' + statements[currentStatement].text + '" (' + (currentStatement+1).toString()+ '/' + statements.length + ')';
			document.getElementById('currentstatement').innerHTML = statementString;

			lypo.removeClass(disagreeBtn, 'disagree-active');
			lypo.removeClass(agreeBtn, 'agree-active');

			if (positions[statements[currentStatement].id] == 'a') {
				lypo.addClass(agreeBtn, 'agree-active');
			} else if (positions[statements[currentStatement].id] == 'c') {
				lypo.addClass(disagreeBtn, 'disagree-active');
			}
		});

		//request the statements from the lypo server
		gadgets.io.makeRequest(lypo.url('api', 'statement/registration'), function (response) {
			eval('var data = ' + response.data);
			statements = data.data.statements;

			positions = {};
			currentStatement = 0;
			prevBtn.style.display = 'none';
			var statementString = '"' + statements[currentStatement].text + '" (' + (currentStatement+1).toString()+ '/' + statements.length + ')';
			document.getElementById('currentstatement').innerHTML = statementString;
		});
	}


	/**
	 * BUILD THE PAGE WHERE THE PERSONAL INFO IS PUT IN
	 */
	var _buildPersonalInfoPage = function () {
		_pages['register-info'] = new lypo.page('register-info');
		var section = new lypo.section('register-info');
		var activeCategory = 'Character';

		var nameField       = document.getElementById('name');
		var ageField        = document.getElementById('age');
		var genderField     = document.getElementById('gender');
		var originField     = document.getElementById('origin');
		var countryField    = document.getElementById('country');
		var occupationField = document.getElementById('occupation');
		var enemyField      = document.getElementById('enemy');
		var avatarField     = document.getElementById('thumbnail_url');

		try {
			countryField.add(new Option('Select country', '-1'), 0);
		} catch (e) {
			countryField.add(new Option('Select country', '-1'), countryField.options[0]);
		}

		countryField.selectedIndex = 0;

		for (var i=0; i<countryField.options.length; i++) {
			if (countryField.options[i].value == _profileData.country) {
				countryField.selectedIndex = i;
				break;
			}
		}

		//when clicked on the done button send all the updated data to the server
		section.addClickCallback('.done', function () {
			_profileData.name          = nameField.value;
			_profileData.age           = ageField.value == '-1' ? '' : ageField.options[ageField.selectedIndex].value;
			_profileData.gender        = genderField.value;
			_profileData.origin        = originField.value;
			_profileData.country       = countryField.value == '-1' ? '' : countryField.options[countryField.selectedIndex].text;
			_profileData.occupation    = occupationField.value;
			_profileData.keywords      = selectedKeywords;
			_profileData.thumbnail_url = avatarField.value;
			_profileData.enemy         = enemyField.value;

			_storeLypoData('create', function () {
				lypo.gadget.goToPage('home');
			});
		});

		//open or close the keywords section
		section.addClickCallback('.open-keywords', function () {
			if (lypo.hasClass(document.getElementById('keywords'), 'hide')) {
				lypo.removeClass(document.getElementById('keywords'), 'hide');
				lypo.removeClass(document.getElementById('keyword-presets'), 'hide');
			} else {
				lypo.addClass(document.getElementById('keywords'), 'hide');
			}
		});

		//close the keyword presets
		section.addClickCallback('.close-keywords', function () {
			lypo.addClass(document.getElementById('keywords'), 'hide');
		});

		//when clicked on a category show the selection of keywords
		section.addClickCallback('.keyword-category', function () {
			//set all the other categories back to normal font case
			for (var span=this.parentNode.firstChild; span!=null; span=span.nextSibling) {
				if (span.nodeName != '#text') {
					span.style.fontWeight = 'normal';
				}
			}

			this.style.fontWeight = 'bold';

			//hide all the categories
			var keywordPresets = document.getElementById('keyword-presets');
			var paragraphs = keywordPresets.getElementsByTagName('p');
			var categories = new Array();

			for (var i=0; i<paragraphs.length; i++) {
				if (lypo.hasClass(paragraphs[i], 'category'))
					lypo.addClass(paragraphs[i], 'hide');

				categories.push(paragraphs[i]);
			}

			//find the needed category
			activeCategory = this.innerHTML;

			var category = this.innerHTML.toLowerCase();
			category = category.replace('\'', '');
			category = category.replace('"', '');
			category = category.replace(' ', '-');
			category = 'category-' + category;

			//show the category
			for (var i=0; i<categories.length; i++) {
				if (lypo.hasClass(categories[i], category))
					lypo.removeClass(categories[i], 'hide');
			}
		});

		var selectedKeywords = new Array(); //array to hold all the selected keywords. done so multiple callbacks have access

		//adds a keyword either from the input fields or the presets
		function addKeyword () {
			var keyword;
			var category;

			if (lypo.hasClass(this, 'keyword')) {
				keyword = this.innerHTML;
				category = activeCategory;
			} else if (lypo.hasClass(this, 'add-keyword')) {
				keyword = document.getElementById('add-own').value;
				category = 'My own';
			}

			keyword = keyword.replace(/^\s+/, '');
			keyword = keyword.replace(/\s+$/, '');

			//search the selected keywords to see it is already selected
			if (selectedKeywords[category]) {
				for (var i in selectedKeywords[category])
					if (selectedKeywords[category][i] == keyword) return;
			} else {
				selectedKeywords[category] = new Array();
			}

			selectedKeywords[category].push(keyword);

			//keyword was not previously selected
			var chosenKeywords  = document.getElementById('chosen-keywords');
			var categoryHeaders = chosenKeywords.getElementsByTagName('h4');
			var keywordsHolder;
			var categoryExists = false;

			//walk through all the headers with the category names and find the correct one
			if (categoryHeaders.length > 0) {
				for (var i=0; i<categoryHeaders.length; i++) {
					if (categoryHeaders[i].innerHTML == category) {
						categoryExists = true;

						if (categoryHeaders[i].nextSibling.nodeName == '#text') {
							keywordsHolder = categoryHeaders[i].nextSibling.nextSibling;
						} else {
							keywordsHolder = categoryHeaders[i].nextSibling;
						}

						break;
					}
				}
			} else {
				chosenKeywords.innerHTML = '';
			}

			//if this is the first keyword in this category create a dom fragment for it
			if (!categoryExists) {
				var wrapper = document.createElement('div');
				var categoryHeader = document.createElement('h4');
				categoryHeader.innerHTML = category;
				keywordsHolder = document.createElement('div');

				wrapper.appendChild(categoryHeader);
				wrapper.appendChild(keywordsHolder);

				chosenKeywords.appendChild(wrapper);
			} else {
				keywordsHolder.appendChild(document.createTextNode(', '))
			}

			//build the span with the keyword
			var keywordSpan = document.createElement('span');
			keywordSpan.className = 'chosen-keyword';
			keywordSpan.innerHTML = keyword;

			keywordsHolder.appendChild(keywordSpan);
		}

		//add a preset or custom keyword
		section.addClickCallback('.keyword', addKeyword);
		section.addClickCallback('.add-keyword', addKeyword);

		//remove a keyword
		section.addClickCallback('.chosen-keyword', function () {
			var chosenKeywords = document.getElementById('chosen-keywords');
			var keywordsHolder = this.parentNode;
			var deletedKeyword = this.innerHTML;
			var category = keywordsHolder.parentNode.getElementsByTagName('h4')[0].innerHTML;

			if (this.nextSibling && this.nextSibling.nodeName == '#text') {
				keywordsHolder.removeChild(this.nextSibling);
			} else if (!(keywordsHolder.lastChild == this && keywordsHolder.firstChild == this)) {
				keywordsHolder.removeChild(this.previousSibling);
			}

			keywordsHolder.removeChild(this);

			for (var i in selectedKeywords[category]) {
				if (selectedKeywords[category][i] == deletedKeyword) {
					selectedKeywords[category].splice(i, 1);
					
					if (selectedKeywords[category].length == 0)
						delete selectedKeywords[category];

					break;
				}
			}

			if (keywordsHolder.getElementsByTagName('span').length == 0)
				chosenKeywords.removeChild(keywordsHolder.parentNode);

			if (chosenKeywords.getElementsByTagName('h4').length == 0)
				chosenKeywords.innerHTML = '<p>No keywords selected</p>';
		});

		//fill the fields with the open social values
		nameField.value       = _profileData.name;
		avatarField.value     = _profileData.thumbnail_url;
		originField.value     = _profileData.origin;
		occupationField.value = _profileData.occupation;
		enemyField.value      = _profileData.enemy;    

		//search for the right age in the <select>
		var ageOptions = ageField.options;
		for (var i=0; i<ageOptions.length; i++) {
			if (ageOptions[i].value == _profileData.age) {
				ageOptions[i].selected = true;
				break;
			}
		}

		//search for the right gender in the <select>
		var genderOptions = genderField.options;
		for (var i=0; i<genderOptions.length; i++) {
			if (genderOptions[i].value == _profileData.gender) {
				genderOptions[i].selected = true;
				break;
			}
		}

		//show the open social avatar
		document.getElementById('avatar').src = avatarField.value;

		//everytime the avatar field is changed show the image
		avatarField.onkeyup = function () {
			document.getElementById('avatar').src = avatarField.value;
		}
	}


	/**
	 * BUILDS THE HOMEPAGE
	 */
	var _buildHomepage = function () {
		var sectionsUpdated = 0;
		var numberSections  = 2;
		var debateOfTheDay  = '';

		_pages['home'] = new lypo.page('home');

		var debatesSection = new lypo.section('home-debates');
		var oppositesSection = new lypo.section('home-opposites');

		function sectionUpdated() {
			var debateToday = document.getElementById('debate-today');
			var currentDebateClass;

			sectionsUpdated++;

			if (sectionsUpdated == numberSections) {
				lypo.gadget.hideLoading();
				sectionsUpdated = 0;

				if (debateToday.firstChild.nodeName == '#text') {
					currentDebateClass = debateToday.firstChild.nextSibling.className;
				} else {
					currentDebateClass = debateToday.firstChild.className;
				}

				debateOfTheDay = currentDebateClass.match(/debate-([0-9]+)/)[1];
				_setDebateOptionsBehaviours('debate-today');
			}
		}

		function castVote() {
			var lastSpan, yesSpan, noSpan;
			var parentSpans = this.parentNode.getElementsByTagName('span');

			for (var i=0; i<parentSpans.length; i++) {
				if (lypo.hasClass(parentSpans[i], 'vote-no')) {
					noSpan = parentSpans[i];
				} else if (lypo.hasClass(parentSpans[i], 'vote-yes')) {
					yesSpan = parentSpans[i];
				} else {
					lastSpan = parentSpans[i];
				}
			}

			if (lypo.hasClass(this, 'vote-yes')) {
				if (lypo.hasClass(this, 'vote-yes-active')) {
					lypo.removeClass(this, 'vote-yes-active');
					lastSpan.innerHTML = 'No opinion';
					answer = '';

				} else {
					lypo.addClass(this, 'vote-yes-active');

					if (lypo.hasClass(noSpan, 'vote-no-active'))
						lypo.removeClass(noSpan, 'vote-no-active');

					lastSpan.innerHTML = 'I agree';
					answer = 'yes';
				}

			} else if (lypo.hasClass(this, 'vote-no')) {
				if (lypo.hasClass(this, 'vote-no-active')) {
					lypo.removeClass(this, 'vote-no-active');
					lastSpan.innerHTML = 'No opinion';
					answer = '';

				} else {
					lypo.addClass(this, 'vote-no-active');

					if (lypo.hasClass(yesSpan, 'vote-yes-active'))
						lypo.removeClass(yesSpan, 'vote-yes-active');

					lastSpan.innerHTML = 'I disagree';
					answer = 'no';
				}
			}

			lypo.gadget.voteOnStatement(debateOfTheDay, answer)
		}

		_pages['home'].addShowCallback(function () {
			lypo.removeClass(document.getElementById('navigation'), 'hide');
			lypo.gadget.showLoading();
			debatesSection.update(lypo.url('frontend', 'home/debates?userid=' + _profileData.userid), sectionUpdated);
			window.setTimeout(function () {
                        	oppositesSection.update(lypo.url('frontend', 'home/opposites?userid=' + _profileData.userid), sectionUpdated);
                        }, 250);
			//oppositesSection.update(lypo.url('frontend', 'home/opposites?userid=' + _profileData.userid), sectionUpdated);
			_setActiveMenuItem('home');

			_track('View', 'homepage');
		});

		debatesSection.addClickCallback('.react-to-debate', function () {
			lypo.gadget.goToDebate(debateOfTheDay, true);
		});

		debatesSection.addClickCallback('.more-debates', function () {
			lypo.gadget.goToPage('debates');
		});

		debatesSection.addClickCallback('.vote-yes', castVote);
		debatesSection.addClickCallback('.vote-no', castVote);

		oppositesSection.addClickCallback('.more-opposites', function () {
			lypo.gadget.goToPage('myopposites');
		})
	}


	/**
	 * BUILDS THE DEBATE PAGE
	 */
	var _buildDebatePage = function () {
		_pages['debate'] = new lypo.page('debate');
		var updatedSections = 0;
		var totalSections   = 2;

		//build the sections of the page
		var statement = new lypo.section('debate-statement');
		var react     = new lypo.section('debate-react');
		var reactions = new lypo.section('debate-reactions');

		//get references to some divs
		var divs = document.getElementById('compose-reaction').getElementsByTagName('div');
		var videoDiv, recorderDiv;

		for (var i=0; i<divs.length; i++) {
			if (lypo.hasClass(divs[i], 'video'))
				videoDiv = divs[i];
			else if (lypo.hasClass(divs[i], 'recorder'))
				recorderDiv = divs[i];
		}

		//get references to some spans
		var spans = document.getElementById('compose-reaction').getElementsByTagName('span');
		var sendReaction;

		for (var i=0; i<spans.length; i++) {
			if (lypo.hasClass(spans[i], 'send-reaction'))
				sendReaction = spans[i];
		}

		//function that updates the 'reactions' section when clicked on a link
		function otherReactions () {
			lypo.gadget.showLoading()
			reactions.update(lypo.parseUrl(this.href), function () {
				lypo.gadget.hideLoading();	
			});
		}

		//callback used to determine if all the sections are updated
		function updateCounter() {
			updatedSections++;

			if (updatedSections == totalSections) {
				lypo.gadget.hideLoading();

				if (_pages['debate'].retrieve('showDebateForm')) {
					lypo.removeClass(document.getElementById('compose-reaction'), 'hide');
				} else {
					lypo.addClass(document.getElementById('compose-reaction'), 'hide');
				}

				_pages['debate'].store('showDebateForm', false);

				_setDebateOptionsBehaviours('debate-detail');

				var commentDivs = document.getElementById('compose-reaction').getElementsByTagName('div');
				var avatar = document.getElementById('compose-reaction').getElementsByTagName('img')[0];
				avatar.src = _profileData.thumbnail_url;

				for (var i=0; i<commentDivs.length; i++) {
					if (lypo.hasClass(commentDivs[i], 'commenter-name')) {
						commentDivs[i].innerHTML = '<strong>' + _profileData.name + '</strong> (' + _profileData.country + ')';
						break;
					}
				}

				var debateTitle = document.getElementById('debate-detail').getElementsByTagName('h3')[0].innerHTML;
				_track('Debate', 'show', debateTitle);
			}
		}

		function castVote() {
			var lastSpan, yesSpan, noSpan, sendAnswer;
			var parentSpans = this.parentNode.getElementsByTagName('span');

			for (var i=0; i<parentSpans.length; i++) {
				if (lypo.hasClass(parentSpans[i], 'vote-no')) {
					noSpan = parentSpans[i];
				} else if (lypo.hasClass(parentSpans[i], 'vote-yes')) {
					yesSpan = parentSpans[i];
				} else {
					lastSpan = parentSpans[i];
				}
			}

			if (lypo.hasClass(this, 'vote-yes')) {
				if (lypo.hasClass(this, 'vote-yes-active')) {
					lypo.removeClass(this, 'vote-yes-active');
					lastSpan.innerHTML = 'No opinion';
					sendAnswer = '';

				} else {
					lypo.addClass(this, 'vote-yes-active');

					if (lypo.hasClass(noSpan, 'vote-no-active'))
						lypo.removeClass(noSpan, 'vote-no-active');

					lastSpan.innerHTML = 'I agree';
					sendAnswer = 'yes';
				}

			} else if (lypo.hasClass(this, 'vote-no')) {
				if (lypo.hasClass(this, 'vote-no-active')) {
					lypo.removeClass(this, 'vote-no-active');
					lastSpan.innerHTML = 'No opinion';
					sendAnswer = '';

				} else {
					lypo.addClass(this, 'vote-no-active');

					if (lypo.hasClass(yesSpan, 'vote-yes-active'))
						lypo.removeClass(yesSpan, 'vote-yes-active');

					lastSpan.innerHTML = 'I disagree';
					sendAnswer = 'no';					
				}
			}

			lypo.gadget.voteOnStatement(_pages['debate'].retrieve('debateId'), sendAnswer)
		}

		statement.addClickCallback('.more-debates', function () {
			lypo.gadget.goToPage('debates');
		});

		statement.addClickCallback('.vote-yes', castVote);
		statement.addClickCallback('.vote-no', castVote);

		reactions.addClickCallback('.nextlink', otherReactions)
		reactions.addClickCallback('.prevlink', otherReactions)

		reactions.addClickCallback('.respect', function () {
			var respectBtn = this;
			var reactionId = respectBtn.className.match(/respect-([0-9]+)/)[1];
			var counter = respectBtn.previousSibling;
			var data = {
				reaction_id: reactionId,
				userid: _profileData.userid
			}

			var params = {};
			params[gadgets.io.RequestParameters.METHOD] = gadgets.io.MethodType.POST;
			params[gadgets.io.RequestParameters.POST_DATA] = gadgets.io.encodeValues(data);

			gadgets.io.makeRequest(lypo.url('api', 'reaction/respect'), function () {
				var trimmed       = counter.nodeValue.replace(/\s/g, '')
				var respectCount  = parseInt(trimmed.substring(1)) + 1;
				var timesChar     = trimmed.substring(0,1);
				counter.nodeValue = ' ' + timesChar + ' ' + respectCount.toString() + ' '; 
				lypo.removeClass(respectBtn, 'respect');

				var debateTitle = document.getElementById('debate-detail').getElementsByTagName('h3')[0].innerHTML;

				_track('Debate', 'respect comment', debateTitle);
			}, params);
		});

		react.addClickCallback('.all-reactions', function () {
			reactions.update(lypo.url('frontend', 'debate/reactions?statement_id='+_pages['debate'].retrieve('debateId') + '&view=all&userid=' + _profileData.userid));
		});

		react.addClickCallback('.perfect-opposite-reactions', function () {
			reactions.update(lypo.url('frontend', 'debate/reactions?statement_id='+_pages['debate'].retrieve('debateId') + '&view=perfectopposites&userid=' + _profileData.userid));
		});

		react.addClickCallback('.no-video', function () {
			lypo.addClass(recorderDiv, 'hide');
			lypo.addClass(videoDiv, 'hide');
			lypo.removeClass(sendReaction, 'disabled');
		});

		react.addClickCallback('.no-video-input', function () {
			lypo.addClass(recorderDiv, 'hide');
			lypo.addClass(videoDiv, 'hide');
			lypo.removeClass(sendReaction, 'disabled');
		});

		//show the video fields. The videoDiv reference was made during construction
		react.addClickCallback('.embed-video', function () {
			lypo.removeClass(videoDiv, 'hide');
			lypo.addClass(recorderDiv, 'hide');
			lypo.removeClass(sendReaction, 'disabled');
		});

		react.addClickCallback('.embed-video-input', function () {
			lypo.removeClass(videoDiv, 'hide');
			lypo.addClass(recorderDiv, 'hide');
			lypo.removeClass(sendReaction, 'disabled');
		});

		//show the recorder. The recorderDiv reference was made during construction
		react.addClickCallback('.create-video', function () {
			lypo.removeClass(recorderDiv, 'hide');
			lypo.addClass(videoDiv, 'hide');
			lypo.addClass(sendReaction, 'disabled');
		});

		react.addClickCallback('.create-video-input', function () {
			lypo.removeClass(recorderDiv, 'hide');
			lypo.addClass(videoDiv, 'hide');
			lypo.addClass(sendReaction, 'disabled');
		});

		//saves a comment to the debate
		react.addClickCallback('.send-reaction', function () {
			if (lypo.hasClass(this, 'disabled')) return;

			//collect data
			var comment = document.getElementById('comment').value;

			var data = {
				content: comment,
				statement_id: _pages['debate'].retrieve('debateId'),
				userid: _profileData.userid,
				embed_code: document.getElementById('embedcode').value
			};

			if (document.getElementById('seesmic_url').value != '')
				data.embed_link = document.getElementById('seesmic_url').value;
			else
				data.embed_link = document.getElementById('videolink').value

			//build request parameters
			var params = {};
			params[gadgets.io.RequestParameters.POST_DATA] = gadgets.io.encodeValues(data);
			params[gadgets.io.RequestParameters.METHOD]    = gadgets.io.MethodType.POST;

			//execute post and update reactions section when done.
			gadgets.io.makeRequest(lypo.url('api', 'reaction/save'), function () {
				reactions.update(lypo.url('frontend', 'debate/reactions?statement_id='+_pages['debate'].retrieve('debateId') + '&view=all&userid=' + _profileData.userid));
				document.getElementById('comment').value = '';
				lypo.addClass(document.getElementById('compose-reaction'), 'hide');

				var debateTitle = document.getElementById('debate-detail').getElementsByTagName('h3')[0].innerHTML;

				_track('Debate', 'post comment', debateTitle);
			}, params);
		});

		//called when the page is shown. Updates all the section and handles the showing and hiding of the loading screen
		_pages['debate'].addShowCallback(function () {
			updatedSections = 0;
			lypo.gadget.showLoading();
			statement.update(lypo.url('frontend', 'debate/main?statement_id='+_pages['debate'].retrieve('debateId') + '&userid=' + _profileData.userid), updateCounter);
			reactions.update(lypo.url('frontend', 'debate/reactions/?statement_id='+_pages['debate'].retrieve('debateId') + '&view=all&userid=' + _profileData.userid), updateCounter);
			_setActiveMenuItem('debates');
			seesmic.player.createRecorder(recorderDiv, 'LYPO', '');
			document.getElementById('no-video').checked = true;
		});
	}


	/**
	 * BUILDS THE DEBATES PAGE
	 */
	var _buildDebatesPage = function () {
		_pages['debates'] = new lypo.page('debates');

		var debatesListSection = new lypo.section('debates-list');

		debatesListSection.addClickCallback('.nextlink', changeList);
		debatesListSection.addClickCallback('.prevlink', changeList);

		function changeList (e) {
			var updateURL = this.href.replace(/http:\/\/[^\/]+/gi, '');

			if (e.preventDefault) {
				e.preventDefault();
			} else {
				e.returnValue = false;
			}

			lypo.gadget.showLoading();
			debatesListSection.update(lypo.parseUrl(this.href), lypo.gadget.hideLoading);
		}

		_pages['debates'].addShowCallback(function () {
			debatesListSection.update(lypo.url('frontend', 'debates/byname?userid=' + _profileData.userid), lypo.gadget.hideLoading);
			_setActiveMenuItem('debates');
			_track('Debates', 'show');
		})
	}


	/**
	 * BUILDS THE PROFILE PAGE
	 */
	var _buildProfilePage = function () {
		var totalSections   = 3;
		var updatedSections = 0;

		_pages['profile'] = new lypo.page('profile');

		var profileInfo       = new lypo.section('profile-info');
		var statementsDebates = new lypo.section('statements-debates');
		var profileOpposites  = new lypo.section('profile-opposites');

		function updateCounter() {
			updatedSections++;

			if (totalSections == updatedSections) {
				updatedSections = 0;

				var profileDetails = document.getElementById('profile_details');
				var width = profileDetails.offsetWidth.toString();
				var paragraphs = profileDetails.getElementsByTagName('p');

				for (var i=0; i<paragraphs.length; i++) {
					if (lypo.hasClass(paragraphs[i], 'meta')) {
						paragraphs[i].style.width = width + 'px';
					}
				}

				var userName = document.getElementById('profile_details').getElementsByTagName('dd')[0].innerHTML;

				_track('Profile', 'show', userName);

				lypo.gadget.hideLoading();
			}
		}

		//pagination function for statements/debates
		function differentPage(e, link) {
			if (e.preventDefault) {
				e.preventDefault();
			} else {
				e.returnValue = false;
			}

			lypo.gadget.showLoading();
			statementsDebates.update(lypo.parseUrl(link.href), lypo.gadget.hideLoading);
		}

		//function to add or remove someone as a perfect opposite
		function perfectOpposite() {
			var divs = document.getElementById('profile_details').getElementsByTagName('div');
			var oppositionDiv, url, callback;
			var data = {
				userid: _profileData.userid,
				opposite_id: _pages['profile'].retrieve('lypoId')
			}

			var params = {};
			params[gadgets.io.RequestParameters.METHOD] = gadgets.io.MethodType.POST;
			params[gadgets.io.RequestParameters.POST_DATA] = gadgets.io.encodeValues(data);
			
			var button = this;

			//weed through the divs to find the one with the badge
			for (var i=0; i<divs.length; i++) {
				if (lypo.hasClass(divs[i], 'not-perfect-opposite') || lypo.hasClass(divs[i], 'is-perfect-opposite')) {
					oppositionDiv = divs[i];
					break;
				}
			}

			//if the action is to add a perfect opposite, create the url, callback function and parameters object 
			if (lypo.hasClass(this, 'add-perfect-opposite')) {
				url = lypo.url('api', 'user/addopposite');

				callback = function () {
					lypo.removeClass(oppositionDiv, 'not-perfect-opposite');
					lypo.addClass(oppositionDiv, 'is-perfect-opposite');
					lypo.removeClass(button, 'add-perfect-opposite');
					lypo.addClass(button, 'remove-perfect-opposite');
					button.innerHTML = 'Remove perfect opposite';
				}

			//if the action is to remove a perfect opposite, create the url, callback function and parameters object
			} else if (lypo.hasClass(this, 'remove-perfect-opposite')) {
				url = lypo.url('api', 'user/removeopposite');

				callback = function () {
					lypo.removeClass(oppositionDiv, 'is-perfect-opposite');
					lypo.addClass(oppositionDiv, 'not-perfect-opposite');
					lypo.removeClass(button, 'remove-perfect-opposite');
					lypo.addClass(button, 'add-perfect-opposite');
					button.innerHTML = 'Add perfect opposite';
				}
			}

			gadgets.io.makeRequest(url, callback, params);
		}

		_pages['profile'].addShowCallback(function () {
			lypo.gadget.showLoading();

			var profileId = _pages['profile'].retrieve('lypoId');

			var profileUrl    = lypo.url('frontend', 'otherprofile/profile/?userid=' + _profileData.userid + '&profile_userid=' + profileId);
			var statementsUrl = lypo.url('frontend', 'otherprofile/statements/?userid=' + _profileData.userid + '&profile_userid=' + profileId);
			var oppositesUrl  = lypo.url('frontend', 'otherprofile/opposites/?userid=' + _profileData.userid + '&profile_userid=' + profileId);

			profileInfo.update(profileUrl, updateCounter);
			statementsDebates.update(statementsUrl, updateCounter);
			profileOpposites.update(oppositesUrl, updateCounter);

			statementsDebates.addClickCallback('.nextlink', function (e) {
				differentPage(e, this);
			});

			statementsDebates.addClickCallback('.prevlink', function (e) {
				differentPage(e, this);
			});
		});

		profileInfo.addClickCallback('.add-perfect-opposite', perfectOpposite);
		profileInfo.addClickCallback('.remove-perfect-opposite', perfectOpposite);
	}


	/**
	 * BUILDS THE MYPROFILE PAGE
	 */
	var _buildMyProfilePage = function () {
		var totalSections   = 3;
		var updatedSections = 0;

		function updateCounter() {
			updatedSections++;

			if (updatedSections == totalSections)
				allSectionsLoaded()
		}

		function allSectionsLoaded() {
			updatedSections = 0;
			lypo.gadget.hideLoading();

			//recreate the keywords from the HTML to prevent inconsistencies when a user removes keywords without saving
			var myKeywords = document.getElementById('my-keywords');
			var keywords = myKeywords.getElementsByTagName('span');
			var category = '';
			_profileData.keywords = {};

			for (var i=0; i<keywords.length; i++) {
				category = keywords[i].parentNode.parentNode.getElementsByTagName('h4')[0].innerHTML;
				if (!_profileData.keywords[category])
					_profileData.keywords[category] = new Array();

				_profileData.keywords[category].push(keywords[i].innerHTML);
			}

			while (myKeywords.lastChild && myKeywords.lastChild.nodeName == '#text')
				myKeywords.removeChild(myKeywords.lastChild);

			if (_profileData.country == '') {
				var countryField = document.getElementById('profile-country');
				var selectCountry = new Option('Select country', '-1');

				try {
					countryField.add(selectCountry, 0);
				} catch (e) {
					countryField.add(selectCountry, countryField.options[0]);
				}

				countryField.selectedIndex = 0;
			}
		}

		function differentPage(e) {
			lypo.gadget.showLoading();
			myStatements.update(lypo.parseUrl(this.href), lypo.gadget.hideLoading);

			if (e.preventDefault) {
				e.preventDefault();
			} else {
				e.returnValue = false;
			}
		}

		function changePosition() {
			var statementId = this.className.match(/debate-([0-9]+)/)[1];
			var spans       = this.parentNode.getElementsByTagName('span');
			var yesSpan, noSpan;

			for (var i=0; i<spans.length; i++) {
				if (lypo.hasClass(spans[i], 'vote-yes')) {
					yesSpan = spans[i];
				} else if (lypo.hasClass(spans[i], 'vote-no')) {
					noSpan = spans[i];
				}
			}

			if (lypo.hasClass(this, 'vote-yes')) {
				if (lypo.hasClass(this, 'vote-yes-active')) {
					lypo.gadget.voteOnStatement(statementId, '');
					lypo.removeClass(this, 'vote-yes-active');
				} else {
					lypo.gadget.voteOnStatement(statementId, 'yes');
					lypo.addClass(this, 'vote-yes-active');
					lypo.removeClass(noSpan, 'vote-no-active');
				}

			} else if (lypo.hasClass(this, 'vote-no')) {
				if (lypo.hasClass(this, 'vote-no-active')) {
					lypo.gadget.voteOnStatement(statementId, '');
					lypo.removeClass(this, 'vote-no-active');
				} else {
					lypo.gadget.voteOnStatement(statementId, 'no');
					lypo.addClass(this, 'vote-no-active');
					lypo.removeClass(yesSpan, 'vote-yes-active');
				}
			}
		}

		_pages['myprofile'] = new lypo.page('myprofile');

		//build the sections
		var myInfo       = new lypo.section('my-info');
		var myStatements = new lypo.section('my-statements-debates');
		var people       = new lypo.section('my-people');

		//update all the sections
		_pages['myprofile'].addShowCallback(function () {
			lypo.gadget.showLoading();
			myInfo.update(lypo.url('frontend', 'myprofile/profile?userid=' + _profileData.userid), function () {
				var chosenKeywords    = document.getElementById('my-keywords').getElementsByTagName('span');
				var keywordSpans      = document.getElementById('myprofile_keywords').getElementsByTagName('span');
				var availableKeywords = new Array();

				//make an array with references to the keywords
				for (var i=0; i<keywordSpans.length; i++) {
					if (lypo.hasClass(keywordSpans[i], 'keyword'))
						availableKeywords.push(keywordSpans[i]);
				}

				//walk through the chosen keywords. Set mouseover/mouseouts events and mark the keywords as selected
				//in the available keywords lists
				for (var i=0; i<chosenKeywords.length; i++) {
					if (lypo.hasClass(chosenKeywords[i], 'chosen-keyword')) {
						chosenKeywords[i].onmouseover = function () {
							if (lypo.hasClass(document.getElementById('myprofile_details'), 'edit'))
								this.style.textDecoration = 'line-through';
						}

						chosenKeywords[i].onmouseout = function () {
							if (lypo.hasClass(document.getElementById('myprofile_details'), 'edit'))
								this.style.textDecoration = 'underline';
						}

						for (var j=0; j<availableKeywords.length; j++) {
							if (availableKeywords[j].innerHTML == chosenKeywords[i].innerHTML)
								lypo.addClass(availableKeywords[j], 'selected');
						}
					} else {
						continue;
					}
				}

				updateCounter();
			});

			myStatements.update(lypo.url('frontend', 'myprofile/mystatements?userid=' + _profileData.userid), updateCounter);
			people.update(lypo.url('frontend', 'myprofile/others?userid=' + _profileData.userid), updateCounter);

			_setActiveMenuItem('my-profile');

			_track('My profile', 'show');
		});

		myInfo.addClickCallback('.edit-profile', function () {
			lypo.addClass(document.getElementById('myprofile_details'), 'edit');
			lypo.addClass(document.getElementById('myprofile_keywords'), 'edit');

			var spans = document.getElementById('myprofile_keywords').getElementsByTagName('span');

			for (var i=0; i<spans.length; i++) {
				if (lypo.hasClass(spans[i], 'chosen-keyword')) {
					spans[i].style.textDecoration = 'underline';
				}
			}

			if (typeof(_profileData.keywords) == 'string') {
				_profileData.keywords = lypo.keywords.objectify(_profileData.keywords);
			}
		});

		var activeCategory = 'Character';

		// select another keyword category
		myInfo.addClickCallback('.keyword-category', function () {
			var pTags       = document.getElementById('myprofile_keywords').getElementsByTagName('p');
			var keywordCode = this.innerHTML.toLowerCase().replace(' ', '-');
			activeCategory  = this.innerHTML;

			for (var i=0; i<pTags.length; i++) {
				if (lypo.hasClass(pTags[i], 'category')) {
					if (lypo.hasClass(pTags[i], 'category-'+keywordCode)) {
						lypo.removeClass(pTags[i], 'hide');
					} else {
						lypo.addClass(pTags[i], 'hide');
					}
				}
			}

			for (var child=this.parentNode.firstChild; child!=null; child=child.nextSibling) {
				if (child.nodeName != '#text')
					lypo.removeClass(child, 'selected');
			}

			lypo.addClass(this, 'selected');
		});

		//select a keyword
		myInfo.addClickCallback('.keyword', function () {
			if (_profileData.keywords[activeCategory]) {
				for (var i=0; i<_profileData.keywords[activeCategory].length; i++) {
					if (_profileData.keywords[activeCategory][i] == this.innerHTML)
						return;
				}
			} else {
				_profileData.keywords[activeCategory] = new Array();
			}

			_profileData.keywords[activeCategory].push(this.innerHTML);
			lypo.addClass(this, 'selected');

			var newKeyword = document.createElement('span');
			newKeyword.innerHTML = this.innerHTML;
			newKeyword.className = 'chosen-keyword';
			newKeyword.style.textDecoration = 'underline';

			var categoryHeaders = document.getElementById('my-keywords').getElementsByTagName('h4');

			if (categoryHeaders.length == 0) {
				document.getElementById('my-keywords').innerHTML = '';
			} else {
				for (var i = 0; i < categoryHeaders.length; i++) {
					if (categoryHeaders[i].innerHTML == activeCategory) {
						var keywordsHolder = categoryHeaders[i].parentNode.getElementsByTagName('p')[0];
						break;
					}
				}
			}

			if (!keywordsHolder) {
				var categoryHeader = document.createElement('h4');
				categoryHeader.appendChild(document.createTextNode(activeCategory));
				var keywordsHolder = document.createElement('p');
				var wrapper        = document.createElement('div');

				wrapper.appendChild(categoryHeader);
				wrapper.appendChild(keywordsHolder);

				document.getElementById('my-keywords').appendChild(wrapper);
			} else {
				while (keywordsHolder.lastChild.nodeName == '#text')
					keywordsHolder.removeChild(keywordsHolder.lastChild);

				keywordsHolder.appendChild(document.createTextNode(', '));
			}

			keywordsHolder.appendChild(newKeyword);
		});

		//remove a keyword
		myInfo.addClickCallback('.chosen-keyword', function () {
			if (!lypo.hasClass(document.getElementById('myprofile_keywords'), 'edit'))
				return;

			var category = this.parentNode.parentNode.getElementsByTagName('h4')[0].innerHTML;
			var keyword  = this.innerHTML;
			var keywordsHolder = this.parentNode;

			for (var i=0; i<_profileData.keywords[category].length; i++) {
				if (_profileData.keywords[category][i] == keyword) {
					_profileData.keywords[category].splice(i, 1);

					if (this.nextSibling)
						keywordsHolder.removeChild(this.nextSibling);
					else if (this.previousSibling)
						keywordsHolder.removeChild(this.previousSibling);

					keywordsHolder.removeChild(this);

					break;
				}
			}

			if (keywordsHolder.getElementsByTagName('span').length == 0) 
				keywordsHolder.parentNode.parentNode.removeChild(keywordsHolder.parentNode);

			var keywordSpans = document.getElementById('myprofile_keywords').getElementsByTagName('span');

			for (var i=0; i<keywordSpans.length; i++) {
				if (lypo.hasClass(keywordSpans[i], 'keyword') && lypo.hasClass(keywordSpans[i], 'selected')) {
					if (keywordSpans[i].innerHTML == keyword) {
						lypo.removeClass(keywordSpans[i], 'selected')
						break;
					}
				}
			}
		});

		//when the save button is clicked set all the info in the spans and send to the lypo server
		myInfo.addClickCallback('.save-profile', function () {
			_profileData.name    = document.getElementById('profile-name').value;
			_profileData.gender  = document.getElementById('profile-gender').options[document.getElementById('profile-gender').selectedIndex].value;
			_profileData.origin  = document.getElementById('profile-origin').value;
			_profileData.show_profile = document.getElementById('profile-showprofile').checked ? '1' : '0';

			var ageField = document.getElementById('profile-age');
			if (ageField.options[ageField.selectedIndex].value == '-1')
				_profileData.age = '';
			else
				_profileData.age = ageField.options[ageField.selectedIndex].value;

			var countryField = document.getElementById('profile-country');
			if (countryField.options[countryField.selectedIndex].value == '-1')
				_profileData.country = '';
			else
				_profileData.country = countryField.options[countryField.selectedIndex].text;

			_profileData.occupation    = document.getElementById('profile-occupation').value;
			_profileData.enemy         = document.getElementById('profile-enemy').value;
			_profileData.thumbnail_url = document.getElementById('profile-avatar').value;

			var nameSpan       = document.getElementById('profile-name').parentNode.getElementsByTagName('span')[0];
			var ageSpan        = document.getElementById('profile-age').parentNode.getElementsByTagName('span')[0];
			var genderSpan     = document.getElementById('profile-gender').parentNode.getElementsByTagName('span')[0];
			var originSpan     = document.getElementById('profile-origin').parentNode.getElementsByTagName('span')[0];
			var countrySpan    = document.getElementById('profile-country').parentNode.getElementsByTagName('span')[0];
			var occupationSpan = document.getElementById('profile-occupation').parentNode.getElementsByTagName('span')[0];
			var enemySpan      = document.getElementById('profile-enemy').parentNode.getElementsByTagName('span')[0];

			nameSpan.innerHTML = _profileData.name + '&nbsp;';
			ageSpan.innerHTML  = _profileData.age + '&nbsp;';

			genderSpan.innerHTML = _profileData.gender == 'f' ? 'female' : 'male';
			originSpan.innerHTML = _profileData.origin + '&nbsp;';

			if (countryField.options[countryField.selectedIndex].value == '-1')
				countrySpan.innerHTML = '&nbsp;';
			else
				countrySpan.innerHTML = countryField.options[countryField.selectedIndex].text;

			occupationSpan.innerHTML = _profileData.occupation + '&nbsp;';
			enemySpan.innerHTML      = _profileData.enemy + '&nbsp;';

			_storeLypoData('update');
			lypo.removeClass(document.getElementById('myprofile_details'), 'edit');
			lypo.removeClass(document.getElementById('myprofile_keywords'), 'edit');

			var spans = document.getElementById('myprofile_keywords').getElementsByTagName('span');

			for (var i=0; i<spans.length; i++) {
				if (lypo.hasClass(spans[i], 'chosen-keyword')) {
					spans[i].style.textDecoration = 'none';
				}
			}

			document.getElementById('nametag').getElementsByTagName('span')[0].innerHTML = _profileData.name;
			document.getElementById('nametag').getElementsByTagName('img')[0].src = _profileData.thumbnail_url;
		});

		myStatements.addClickCallback('.nextlink', differentPage);
		myStatements.addClickCallback('.prevlink', differentPage);

		//changes the users vote on that particular statement
		myStatements.addClickCallback('.vote-yes', changePosition);
		myStatements.addClickCallback('.vote-no', changePosition);

		myInfo.addClickCallback('.generate-code', function () {
			gadgets.io.makeRequest(lypo.url('api', 'user/networkcode?userid=' + _profileData.userid), function (response) {
				eval ('var data = ' + response.data);

				if (!data.data.error) {
					var connectCode = document.getElementById('networks').getElementsByTagName('input')[0];
					connectCode.value = data.data.code;
				}
			});
		});

		myInfo.addClickCallback('.go-to-network', function () {
			var selects = document.getElementById('networks').getElementsByTagName('select');
			window.open(selects[0].options[selects[0].selectedIndex].value);
		});
	}


	/**
	 * BUILDS THE MY OPPOSITES PAGE
	 */
	var _buildMyOppositesPage = function() {
		var totalSections   = 2;
		var updatedSections = 0;

		_pages['myopposites'] = new lypo.page('my-opposites');

		var myPerfectOpposites = new lypo.section('my-perfect-opposites');
		var oppositesRespects  = new lypo.section('opposites-respects');

		function updateCounter(){
			updatedSections++;
			
			if (updatedSections == totalSections) {
				updatedSections = 0;
				lypo.gadget.hideLoading();
			}
		}

		function differentPage(e) {
			if (e.preventDefault) {
				e.preventDefault();
			} else {
				e.returnValue = false;
			}

			lypo.gadget.showLoading();
			oppositesRespects.update(lypo.parseUrl(this.href), lypo.gadget.hideLoading)
		}

		_pages['myopposites'].addShowCallback(function () {
			lypo.gadget.showLoading();
			myPerfectOpposites.update(lypo.url('frontend', 'myopposites/perfectopposites?userid=' + _profileData.userid), updateCounter);
			oppositesRespects.update(lypo.url('frontend', 'myopposites/opposites?userid=' + _profileData.userid), updateCounter);

			_setActiveMenuItem('my-opposites');

			_track('My opposites', 'show');
		});

		oppositesRespects.addClickCallback('.nextlink', differentPage);
		oppositesRespects.addClickCallback('.prevlink', differentPage);
	}


	/**
	 * BUILDS THE ABOUT PAGE
	 */
	var _buildAboutPage = function () {
		_pages['about'] = new lypo.page('about');

		_pages['about'].addShowCallback(function () {
			_setActiveMenuItem('about-lypo');

			_track('About', 'show');
		});
	}


	/**
	 * BUILDS THE DASHBOARD ON THE LEFT SIDE
	 */
	var _buildDashboard = function () {
		var navigation = new lypo.section('navigation');

		navigation.addClickCallback('.to-home', function () {
			lypo.gadget.goToPage('home');
		});

		navigation.addClickCallback('.to-debates', function () {
			lypo.gadget.goToPage('debates');
		});

		navigation.addClickCallback('.to-profile', function () {
			lypo.gadget.goToPage('myprofile');
		});

		navigation.addClickCallback('.to-opposites', function () {
			lypo.gadget.goToPage('myopposites');
		});
		
		navigation.addClickCallback('.to-about', function () {
			lypo.gadget.goToPage('about');
		});
	}


	/**
	 * SETS COMMON CALLBACKS USED THROUGHOUT THE APPLICATION
	 */
	var _globalCallbacks = function () {
		var section = new lypo.section('canvas');

		section.addClickCallback('.tab', function () {
			//set all the tabs to inactive
			var tabList = this.parentNode;
			for (var li=tabList.firstChild; li!=null; li=li.nextSibling) {
				if (li.nodeName != '#text')
					lypo.removeClass(li, 'active');
			}

			//hide all the panels
			for (var div=tabList.nextSibling; div!=null; div=div.nextSibling) {
				if (div.nodeName != '#text' && lypo.hasClass(div, 'content'))
					lypo.addClass(div, 'hide');
			}

			//set the clicked tab to active and unhide its corresponding content panel
			lypo.addClass(this, 'active');
			var contentPanelId = this.id.replace(/^tab\-/g, '');
			lypo.removeClass(document.getElementById(contentPanelId), 'hide');
		});

		section.addClickCallback('.profile', function () {
			var profileIdClassname = this.className.match(/profile-[^\s]+/)[0];
			profileId = profileIdClassname.replace(/^profile-/, '');

			lypo.gadget.goToProfile(profileId);
		});

		section.addClickCallback('.debate', function () {
			var debateId = this.className.match(/debate-([0-9]+)/)[1];

			if (debateId == _pages['debate'].retrieve('debateId') && !lypo.hasClass(document.getElementById('debate'), 'hide')) {
				lypo.removeClass(document.getElementById('compose-reaction'), 'hide');
				return;
			}

			lypo.gadget.goToDebate(debateId);
		});
	}

	//return object as lypo.gadget with public members and methods
	return {
		init: function () {
			gadgets.window.adjustHeight(550);

			pageTracker = _gat._getTracker('UA-1263052-13');
			pageTracker._initData();

			if (document.getElementById('canvas').offsetWidth > 950)
				document.getElementById('canvas').style.width = '950px';

			lypo.gadget.showLoading();

			_getSocialNetworkData(function () { //get the user data from the social network container
				_getLypoData(function (response) { //get the user data from the lypo server
					eval('var lypoData = ' + response.data);

					_globalCallbacks();
					_buildHomepage();
					_buildDebatesPage();
					_buildDebatePage();
					_buildProfilePage();
					_buildMyProfilePage();
					_buildMyOppositesPage();
					_buildDashboard();
					_buildAboutPage();

					lypoSignature = lypoData.data.user ? lypoData.data.user.lypo_signature : '';

					if (lypoData.error == true || lypoSignature.split(' ').length < 20) { //the current user is new and needs to answer a few questions for oppositeness determination
						document.getElementById('nametag').getElementsByTagName('span')[0].innerHTML = _profileData.name;
						document.getElementById('nametag').getElementsByTagName('img')[0].src = _profileData.thumbnail_url;

						_buildPreRegChoice();
						lypo.gadget.goToPage('preregister-choice');

						lypo.gadget.hideLoading();

					} else { //the current user is not new. Go to the homepage instead of the register page
						_profileData.name       = lypoData.data.user.name;
						_profileData.age        = lypoData.data.user.age;
						_profileData.gender     = lypoData.data.user.gender;
						_profileData.origin     = lypoData.data.user.origin;
						_profileData.occupation = lypoData.data.user.occupation;
						_profileData.enemy      = lypoData.data.user.enemy;
						_profileData.keywords   = lypo.keywords.objectify(lypoData.data.user.keywords);
						_profileData.thumbnail_url = lypoData.data.user.thumbnail_url;

						document.getElementById('nametag').getElementsByTagName('span')[0].innerHTML = _profileData.name;
						document.getElementById('nametag').getElementsByTagName('img')[0].src = _profileData.thumbnail_url;

						lypo.removeClass(document.getElementById('navigation'), 'hide');

						document.getElementById('register-statements').parentNode.removeChild(document.getElementById('register-statements'));
						document.getElementById('register-info').parentNode.removeChild(document.getElementById('register-info'));
						lypo.gadget.hideLoading();
						lypo.gadget.goToPage('home');
					}
				});
			});
		},

		//shows one page and hides the others 
		goToPage: function (pageId) {
			for (var i in _pages) {
				if (i == pageId) {
					_pages[i].show();
				} else {
					_pages[i].hide();
				}
			}
		},

		//go to an debate
		goToDebate: function (debateId, showForm) {
			showDebateForm = showForm || false;

			_pages['debate'].store('debateId', debateId);
			_pages['debate'].store('showDebateForm', showDebateForm);

			this.goToPage('debate');
		},

		//show the profile of a lypo member
		goToProfile: function (lypoId) {
			_pages['profile'].store('lypoId', lypoId);

			this.goToPage('profile');
		},

		//store the vote of a person for a statement 
		voteOnStatement: function (statementId, vote, callback) {
			var answer;

			if (vote == 'yes') {
				answer = 'a'; 
			} else if (vote == 'no') {
				answer = 'c';
			} else {
				answer = 'b';
			}

			var data = {
				statement_id: statementId,
				answer: answer,
				userid: _profileData.userid
			}

			var params = {};
			params[gadgets.io.RequestParameters.POST_DATA] = gadgets.io.encodeValues(data);
			params[gadgets.io.RequestParameters.METHOD]    = gadgets.io.MethodType.POST;

			gadgets.io.makeRequest(lypo.url('api', 'statement/saveanswer'), callback, params);
		},

		showLoading: function () {
			var panelWidth = gadgets.window.getViewportDimensions().width - 280;
			document.getElementById('loading').style.width = panelWidth.toString() + 'px';
			
			_loadingTimeout = window.setTimeout(function () {
				lypo.removeClass(document.getElementById('loading'), 'hide');
			}, 750);
		},

		hideLoading: function () {
			lypo.addClass(document.getElementById('loading'), 'hide');
			window.clearTimeout(_loadingTimeout);
		}
	}
})();
gadgets.util.registerOnLoadHandler(lypo.gadget.init);